package cn.glfs.domain.strategy.service;



import cn.glfs.domain.strategy.model.entity.StrategyAwardEntity;
import cn.glfs.domain.strategy.model.entity.RaffleFactorEntity;
import cn.glfs.domain.strategy.model.enums.LogicChainModel;
import cn.glfs.domain.strategy.model.valobj.LogicChainAwardVO;
import cn.glfs.domain.strategy.model.entity.RaffleAwardEntity;
import cn.glfs.domain.strategy.model.valobj.LogicTreeAwardVO;
import cn.glfs.domain.strategy.repository.IStrategyRepository;
import cn.glfs.domain.strategy.service.armory.IStrategyDispatch;
import cn.glfs.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import cn.glfs.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import cn.glfs.types.enums.ResponseCode;
import cn.glfs.types.exception.AppException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

/**
 * 抽奖策略抽象类，定义抽奖的标准流程
 */
@Slf4j
public abstract class AbstractRaffleStrategy implements IRaffleStrategy {

    protected IStrategyRepository repository;
    // 单一职责：只关系抽奖的装配和实际抽奖动作，不关心你怎么抽，减少代码耦合
    protected IStrategyDispatch strategyDispatch;
    // 从抽奖的规则中，解耦出前置规则为责任链处理，通过工厂构建一条责任链
    protected final DefaultChainFactory defaultChainFactory;
    // 负责抽奖中到抽奖后的规则过滤，如抽奖到A奖品ID，之后要做次数的判断和库存的扣减等，通过工厂构建一颗规则树
    protected final DefaultTreeFactory defaultTreeFactory;

    public AbstractRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch, DefaultChainFactory defaultChainFactory, DefaultTreeFactory defaultTreeFactory) {
        this.repository = repository;
        this.strategyDispatch = strategyDispatch;
        this.defaultChainFactory = defaultChainFactory;
        this.defaultTreeFactory = defaultTreeFactory;
    }

    /**
     * 抽奖接口
     * 0.概率装配，权重装配
     * 1.策略规则 -> 奖品id （有不同策略，所以给出多个不同的装配策略规则的路线）
     * 2.奖品规则 -> 抽奖后奖品下发规则 （有不同奖品规则装配路线，所以给出多个不同的装配奖品规则的路线）
     * @param RaffleFactorEntity
     */
    public RaffleAwardEntity performRaffle(RaffleFactorEntity RaffleFactorEntity){
        // 1. 参数校验
        String userId = RaffleFactorEntity.getUserId();
        Long strategyId = RaffleFactorEntity.getStrategyId();
        if (StringUtils.isEmpty(userId) || null == strategyId) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }

        // 2.责任链抽奖获取奖品id，若为兜底奖品之间返回（因为兜底奖品不限制库存）
        LogicChainAwardVO logicChainAwardVO = raffleLogicChain(userId, strategyId);
        log.info("抽奖策略计算-责任链 {} {} {} {}", userId, strategyId, logicChainAwardVO.getAwardId(), logicChainAwardVO.getLogicModel());
        if (!LogicChainModel.RULE_DEFAULT.getCode().equals(logicChainAwardVO.getLogicModel())) {
            return buildRaffleAwardEntity(strategyId, logicChainAwardVO.getAwardId(), null);
        }

        // 3.规则树抽奖，根据奖品id走对应的抽奖流程
        LogicTreeAwardVO logicTreeAwardVO = raffleLogicTree(userId, strategyId, logicChainAwardVO.getAwardId());
        log.info("抽奖策略计算-规则树 {} {} {} {}", userId, strategyId, logicTreeAwardVO.getAwardId(), logicTreeAwardVO.getAwardRuleValue());

        return buildRaffleAwardEntity(strategyId, logicTreeAwardVO.getAwardId(), logicTreeAwardVO.getAwardRuleValue());
    }

    // 责任链抽奖
    public abstract LogicChainAwardVO raffleLogicChain(String userId, Long strategyId);

    public abstract LogicTreeAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId);

    private RaffleAwardEntity buildRaffleAwardEntity(Long strategyId, Integer awardId, String awardConfig) {
        StrategyAwardEntity strategyAward = repository.queryStrategyAwardEntity(strategyId, awardId);
        return RaffleAwardEntity.builder()
                .awardId(awardId)
                .awardConfig(awardConfig)
                .sort(strategyAward.getSort())
                .build();
    }

}
